home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 262_01.zip / PROFILE.C < prev    next >
Text File  |  1993-04-14  |  8KB  |  232 lines

  1. /****************************************************************
  2.  *                     Execution Time Profiler                  *
  3.  *                         By Robert Ramey                      *
  4.  *                        21 December 1986                      *
  5.  ****************************************************************/
  6.  
  7. /* This program is used to determine where another program is   */
  8. /* spending its time.  To use it link in profile as the first   */
  9. /* module in the program.  Then execute with PROFILE instead of */
  10. /* the program name.  When program terminates there will be a   */
  11. /* file on the current disk named PROFILE which will contain a  */
  12. /* table of the number of timer interrupts that occurred in each*/
  13. /* subroutine.  In my system, a timer interrupt is produced ten */
  14. /* times per second.   Hence the number of seconds spent in each*/
  15. /* function is approximately the number in the table divided by */
  16. /* ten. */
  17.  
  18. /* Programs should function the same with or without profile.   */
  19. /* The only difference is that when exit() is called,  windup() */
  20. /* will be executed.  Only when windup() returns will exit()    */
  21. /* be entered */
  22.  
  23. #define MAXSLOTS    256 /* maximum number of slots */
  24. #define DATASEG (&numslots) /* last address in code segment */
  25. #define CLOCKOFF    2   /* timer interrupt offset */
  26. #define SYMSIZE 7   /* size to reserve for address symbol*/
  27. #define JP  0xc3    /* jump instruction */
  28.  
  29. static int numslots,    /* number of subroutines monitored */
  30.     high, low, middle;/* used in binary search of table */
  31.  
  32. #include <stdio.h>
  33.  
  34. typedef char *ADDRESS;
  35. typedef struct {
  36.     ADDRESS address;    /* address of slot */
  37.     unsigned count;     /* number of ticks in this slot */
  38.     char symbol[SYMSIZE];   /* name assigned to address */
  39.     } HISTOGRAM ;
  40.  
  41. static ADDRESS
  42.     clock,      /* address of timer interrupt handler */
  43.     retaddr,    /* address at timer interrupt */
  44.     warmstart,  /* address of warmstart routine */
  45.     *iptr;      /* interrupt vector entry for timer */
  46.  
  47. static char oexit[3];   /* original 1st 3 bytes of exit() function */
  48.  
  49. static HISTOGRAM hist[MAXSLOTS];
  50.  
  51. int acompare();
  52. ADDRESS *ir();
  53. void tick(), exit(), windup();
  54.  
  55. /*****************************************************************
  56. setup - make table of addresses and start processing timer
  57. interrupts
  58. ******************************************************************/
  59. void
  60. setup()
  61. {
  62.     register int i;
  63.     ADDRESS addr, *aptr;
  64.     FILE *fp;
  65.     HISTOGRAM tslot[MAXSLOTS], *tptr[MAXSLOTS];
  66.  
  67.     if(!(fp = fopen("PROFILE.SYM","r")))
  68.         error("PROFILE.SYM does not exist");
  69.  
  70.     /* fill in array */
  71.     strcpy(tslot[0].symbol, "PAGE0");
  72.     tslot[0].address = 0;
  73.  
  74.     i = 1;
  75.     /* with addresses from symbol table file */
  76.     while(2 == fscanf(fp, "%x %s", &addr, tslot[i].symbol)){
  77.         if(addr > DATASEG) continue;
  78.         tslot[i].address = addr;
  79.         if(++i == (MAXSLOTS - 2))
  80.             error("Too many addresses");
  81.     }
  82.     fclose(fp);
  83.  
  84.     /* and with CP/M addresses */
  85.     tslot[i].address = *(ADDRESS *)6;
  86.     strcpy(tslot[i].symbol, "ZRDOS");
  87.     tslot[++i].address = *(ADDRESS *)1;
  88.     strcpy(tslot[i].symbol, "BIOS");
  89.  
  90.     /* make array of ptrs for use by qsort() */
  91.     numslots = i + 1;
  92.     for(;i >= 0; --i){
  93.         tptr[i] = &tslot[i];
  94.         tslot[i].count = 0;
  95.     }
  96.     /* sort addresses in ascending order */
  97.     qsort(tptr, numslots, acompare);
  98.  
  99.     /* load into static array */
  100.     for(i = numslots;--i >= 0;)
  101.         memcpy(&hist[i], tptr[i], sizeof(HISTOGRAM));
  102.  
  103.     /* redirect exit() to windup() */
  104.     memcpy(oexit, exit, 3); /*store original 3 bytes of exit()*/
  105.     *(char *)exit = JP;
  106.     *((char *)exit + 1) = windup;
  107.     *((char *)exit + 2) = windup >> 8;
  108.  
  109.     /* redirect warmstart to windup just in case program aborts */
  110.     aptr = (ADDRESS *)(*(ADDRESS *)1 + 1);
  111.     warmstart = *aptr;
  112.     *aptr = windup;
  113.  
  114.     /* redirect timer interrupts to tick() */
  115.     iptr = ir() + CLOCKOFFSET;
  116.     clock = *iptr;      /* save address of timer interrupt */
  117.     *iptr = tick;       /* start counting interrupts */
  118. }
  119. /******************************************************************
  120. windup - executes before normal Q/C exit routine.
  121.     Write histogram to a file PROFILE on currently selected disk.
  122. *******************************************************************/
  123. static void
  124. windup(exitarg)
  125. int exitarg;
  126. {
  127.     register i;
  128.     FILE *fp;
  129.     ADDRESS *aptr;
  130.     unsigned tcnt;
  131.     HISTOGRAM *hptr;
  132.  
  133.     /* restore original contents of exit() */
  134.     memcpy(exit, oexit, 3);
  135.     *iptr = clock;      /* stop counting timer interrupts */
  136.     aptr = (ADDRESS *)(*(ADDRESS *)1 + 1);
  137.     *aptr = warmstart;  /* reload original warmstart */
  138.  
  139.     if(!(fp = fopen("profile", "w")))
  140.         error("Can't open file for execution profile");
  141.  
  142.     /* calculate total number of ticks */
  143.     tcnt = 0;
  144.     for(i = numslots; --i >= 0;) tcnt += hist[i].count;
  145.  
  146.     /* write out profile to disk */
  147.     for(hptr = hist,i = numslots; --i >= 0;++hptr){
  148.         if(hptr->count)
  149.             fprintf(fp,"%s\t%5d\t%3d\n"
  150.             ,hptr->symbol,hptr->count
  151.             ,(hptr->count * 200 + tcnt) / (2 * tcnt));
  152.     }
  153.     fclose(fp);
  154.  
  155.     /* continue on with normal exit processing */
  156.     exit(exitarg);
  157. }
  158. /*****************************************************************
  159. tick - receives control on timer interrupt
  160. ******************************************************************/
  161. static void
  162. tick()
  163. {
  164.     /* save registers which might be altered */
  165. #asm
  166.     push    hl      ;save hl for a second
  167.     ld  hl,(clock?) ;push interrupt address on top of stack
  168.     ex  (sp),hl     ;so that tick() will return to clock
  169.     push    hl      ;save registers to be modified on stack
  170.     push    de      ;Q/C does not modify BC in this case
  171.     push    af
  172.     ld  hl,8        ;get address of interrupted program
  173.     add hl,sp       ;into hl
  174.     call    ?g
  175.     ld  (retaddr?),hl   ;store into static variable
  176.     call    bump?       ;increment histogram
  177.     pop af      ;restore registers
  178.     pop de
  179.     pop hl
  180. #endasm
  181.     /* continue with original interrupt handler */
  182. }
  183. /****************************************************************
  184. bump - increment appropriate counter in histogam
  185. *****************************************************************/
  186. static void
  187. bump()
  188. {
  189.     /* note: local variables should not be declared */
  190.     /* these will make Q/C call a special routine */
  191.     /* which will alter registers that have not been saved */
  192.  
  193.     /* binary search of address table */
  194.     high = numslots;
  195.     low = 0;
  196.     while((high - low) > 1){
  197.         middle = (high + low) / 2;
  198.         if(retaddr >= hist[middle].address)
  199.             low = middle;
  200.         else
  201.             high = middle;
  202.     }
  203.     ++hist[low].count;
  204. }
  205. /***************************************************************
  206. acompare - compare two members of the table
  207. ****************************************************************/
  208. static int
  209. acompare(a, b)
  210. HISTOGRAM *a, *b;
  211. {
  212.     register int i;
  213.     if(a->address == b->address)
  214.         return 0;
  215.     else
  216.         return a->address > b->address ? 1 : -1;
  217. }
  218. /***************************************************************
  219. ir - get value of interrupt pointer register
  220. ****************************************************************/
  221. static ADDRESS *
  222. ir()
  223. {
  224. #asm
  225.     ld  a,i ;load interrupt vector address
  226.     ld  h,a
  227.     in0 l,(033h);for the HD64180
  228. #endasm
  229. }
  230. ******/
  231. static int
  232. aco